/**
 * 
 */
package au.edu.swin.videoshop.posapp.ui.sections;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.ejb.EJB;
import javax.faces.context.FacesContext;
import javax.faces.model.SelectItem;

import au.edu.swin.videoshop.bean.Rental;
import au.edu.swin.videoshop.bean.RentalStatus;
import au.edu.swin.videoshop.bean.Staff;
import au.edu.swin.videoshop.bean.Store;
import au.edu.swin.videoshop.bean.Title;
import au.edu.swin.videoshop.bean.TitleCopy;
import au.edu.swin.videoshop.bean.TitleMedium;
import au.edu.swin.videoshop.service.MiscUtil;
import au.edu.swin.videoshop.service.RentalService;
import au.edu.swin.videoshop.service.StoreService;
import au.edu.swin.videoshop.service.TitleService;

/**
 * @author julie
 *
 */
public class ReportSection {
	private List mAvailableStores;
	
	private Long mSelectedStoreId;
	private Integer mFromDateDay;
	private Integer mFromDateMonth;
	private Integer mFromDateYear;
	private Integer mToDateDay;
	private Integer mToDateMonth;
	private Integer mToDateYear;
	
	
	
	private List mStockReportStores;
	private List mRentalReportStores;
	private List mStaffReportStores;
	
	@EJB
	private TitleService mTitleService;
	
	@EJB
	private StoreService mStoreService;
	
	@EJB
	private RentalService mRentalService;
	
	public List getAvailableStores() {
		if (mAvailableStores == null) {
			FacesContext facesContext = FacesContext.getCurrentInstance();
			UserSection userSection = (UserSection)facesContext.getApplication().evaluateExpressionGet(facesContext, "#{userSection}", UserSection.class);

			if (userSection.getStaff().isSeniorManager()) {
				List stores = mStoreService.findAllStores();
				mAvailableStores = new ArrayList();
				mAvailableStores.add(new SelectItem(null, "All stores"));
				for (Iterator i = stores.iterator(); i.hasNext();) {
					Store store = (Store) i.next();
					mAvailableStores.add(new SelectItem(store.getStoreId(), store.getStoreName()));
				}
			}
			else if (userSection.getStaff().isManager()) {
				mAvailableStores = new ArrayList();
				mAvailableStores.add(new SelectItem(userSection.getStaff().getStore().getStoreId(), userSection.getStaff().getStore().getStoreName()));
			}
		}
		return mAvailableStores;
	}

	/**
	 * @return the selectedStoreId
	 */
	public Long getSelectedStoreId() {
		return mSelectedStoreId;
	}

	/**
	 * @param selectedStoreId the selectedStoreId to set
	 */
	public void setSelectedStoreId(Long selectedStoreId) {
		mSelectedStoreId = selectedStoreId;
	}
	

	/**
	 * @return the fromDateDay
	 */
	public Integer getFromDateDay() {
		return mFromDateDay;
	}

	/**
	 * @param fromDateDay the fromDateDay to set
	 */
	public void setFromDateDay(Integer fromDateDay) {
		mFromDateDay = fromDateDay;
	}

	/**
	 * @return the fromDateMonth
	 */
	public Integer getFromDateMonth() {
		return mFromDateMonth;
	}

	/**
	 * @param fromDateMonth the fromDateMonth to set
	 */
	public void setFromDateMonth(Integer fromDateMonth) {
		mFromDateMonth = fromDateMonth;
	}

	/**
	 * @return the fromDateYear
	 */
	public Integer getFromDateYear() {
		return mFromDateYear;
	}

	/**
	 * @param fromDateYear the fromDateYear to set
	 */
	public void setFromDateYear(Integer fromDateYear) {
		mFromDateYear = fromDateYear;
	}

	/**
	 * @return the toDateDay
	 */
	public Integer getToDateDay() {
		return mToDateDay;
	}

	/**
	 * @param toDateDay the toDateDay to set
	 */
	public void setToDateDay(Integer toDateDay) {
		mToDateDay = toDateDay;
	}

	/**
	 * @return the toDateMonth
	 */
	public Integer getToDateMonth() {
		return mToDateMonth;
	}

	/**
	 * @param toDateMonth the toDateMonth to set
	 */
	public void setToDateMonth(Integer toDateMonth) {
		mToDateMonth = toDateMonth;
	}

	/**
	 * @return the toDateYear
	 */
	public Integer getToDateYear() {
		return mToDateYear;
	}

	/**
	 * @param toDateYear the toDateYear to set
	 */
	public void setToDateYear(Integer toDateYear) {
		mToDateYear = toDateYear;
	}

	/**
	 * @return the stockReportStores
	 */
	public List getStockReportStores() {
		return mStockReportStores;
	}

	/**
	 * @return the rentalReportStores
	 */
	public List getRentalReportStores() {
		return mRentalReportStores;
	}

	/**
	 * @return the staffReportStores
	 */
	public List getStaffReportStores() {
		return mStaffReportStores;
	}

	public String generateStockReport() {
		List titles = mTitleService.findAllTitles();
		
		Map stores = new HashMap();
		List rentals = mRentalService.findRentalsByStatus(RentalStatus.OPEN);
		for (Iterator i = rentals.iterator(); i.hasNext();) {
			Rental rental = (Rental) i.next();
			
			TitleCopy copy = rental.getTitleCopy();
			Title title = copy.getMedium().getTitle();
			
			if (mSelectedStoreId == null || copy.getStore().getStoreId().equals(mSelectedStoreId)) {
				StockReportStore reportStore;
				if (!stores.containsKey(copy.getStore().getStoreId())) {
					reportStore = new StockReportStore(copy.getStore());
					stores.put(copy.getStore().getStoreId(), reportStore);
				}
				else {
					reportStore = (StockReportStore)stores.get(copy.getStore().getStoreId());
				}
				
				reportStore.increaseUnAvailableCopies();
				
				
				StockReportTitle reportTitle;
				if (!reportStore.getTitles().containsKey(title.getTitleId())) {
					reportTitle = new StockReportTitle(title);
					reportStore.getTitles().put(title.getTitleId(), reportTitle);
				}
				else {
					reportTitle = (StockReportTitle)reportStore.getTitles().get(title.getTitleId());
				}
				
				reportTitle.increaseUnAvailableCopies();
			}
		}
		
		
		for (Iterator i = titles.iterator(); i.hasNext();) {
			Title title = (Title) i.next();
			
			for (Iterator j = title.getMedia().iterator(); j.hasNext();) {
				TitleMedium medium = (TitleMedium) j.next();
				
				if (medium.isAvailable()) {
					if (medium.getCopies() != null) {
						for (Iterator k = medium.getCopies().iterator(); k.hasNext();) {
							TitleCopy copy = (TitleCopy) k.next();
							if (mSelectedStoreId == null || copy.getStore().getStoreId().equals(mSelectedStoreId)) {
								StockReportStore reportStore;
								if (!stores.containsKey(copy.getStore().getStoreId())) {
									reportStore = new StockReportStore(copy.getStore());
									stores.put(copy.getStore().getStoreId(), reportStore);
								}
								else {
									reportStore = (StockReportStore)stores.get(copy.getStore().getStoreId());
								}
								
								reportStore.increaseTotalCopies();
								
								
								StockReportTitle reportTitle;
								if (!reportStore.getTitles().containsKey(title.getTitleId())) {
									reportTitle = new StockReportTitle(title);
									reportStore.getTitles().put(title.getTitleId(), reportTitle);
								}
								else {
									reportTitle = (StockReportTitle)reportStore.getTitles().get(title.getTitleId());
								}
								
								reportTitle.increaseTotalCopies();
							}
						}
					}
				}
			}
		}
		
		mStockReportStores = new ArrayList(stores.values());
		
		return null;
	}
	
	
	
	public String generateRentalReport() {
		
		if (mFromDateYear != null && mFromDateMonth != null && mFromDateDay != null &&
			mToDateYear != null && mToDateMonth != null && mToDateDay != null) {
		
			List rentals = mRentalService.findRentalsByRentalDate(
					MiscUtil.getDay(mFromDateYear, mFromDateMonth, mFromDateDay),
					MiscUtil.getDay(mToDateYear, mToDateMonth, mToDateDay));
			Map stores = new HashMap();
			for (Iterator i = rentals.iterator(); i.hasNext();) {
				Rental rental = (Rental) i.next();
				
				TitleCopy copy = rental.getTitleCopy();
				Title title = copy.getMedium().getTitle();
				
				if (mSelectedStoreId == null || copy.getStore().getStoreId().equals(mSelectedStoreId)) {
					RentalReportStore rentalStore;
					if (!stores.containsKey(copy.getStore().getStoreId())) {
						rentalStore = new RentalReportStore(copy.getStore());
						stores.put(copy.getStore().getStoreId(), rentalStore);
					}
					else {
						rentalStore = (RentalReportStore)stores.get(copy.getStore().getStoreId());
					}
					
					rentalStore.increaseTotalNormalCharge(rental.getFirstCharge());
					rentalStore.increaseTotalPenaltyCharge(rental.getFinalCharge());
					
					RentalReportTitle rentalTitle;
					if (!rentalStore.getTitles().containsKey(title.getTitleId())) {
						rentalTitle = new RentalReportTitle(title);
						rentalStore.getTitles().put(title.getTitleId(), rentalTitle);
					}
					else {
						rentalTitle = (RentalReportTitle)rentalStore.getTitles().get(title.getTitleId());
					}
					
					rentalTitle.increaseTotalNormalCharge(rental.getFirstCharge());
					rentalTitle.increaseTotalPenaltyCharge(rental.getFinalCharge());
				}
			}
			
			mRentalReportStores = new ArrayList(stores.values());
		}
		
		return null;
		
	}
	
	public String generateStaffReport() {
		if (mFromDateYear != null && mFromDateMonth != null && mFromDateDay != null &&
			mToDateYear != null && mToDateMonth != null && mToDateDay != null) {
			
				List rentals = mRentalService.findRentalsByRentalDate(
						MiscUtil.getDay(mFromDateYear, mFromDateMonth, mFromDateDay),
						MiscUtil.getDay(mToDateYear, mToDateMonth, mToDateDay));
				Map stores = new HashMap();
				for (Iterator i = rentals.iterator(); i.hasNext();) {
					Rental rental = (Rental) i.next();
					
					TitleCopy copy = rental.getTitleCopy();
					Staff staff = rental.getStaff();
					
					if (mSelectedStoreId == null || copy.getStore().getStoreId().equals(mSelectedStoreId)) {
						StaffReportStore staffStore;
						if (!stores.containsKey(copy.getStore().getStoreId())) {
							staffStore = new StaffReportStore(copy.getStore());
							stores.put(copy.getStore().getStoreId(), staffStore);
						}
						else {
							staffStore = (StaffReportStore)stores.get(copy.getStore().getStoreId());
						}
						
						staffStore.increaseMovieProcessed();
						
						StaffReportTitle staffTitle;
						if (!staffStore.getStaffs().containsKey(staff.getStaffId())) {
							staffTitle = new StaffReportTitle(staff);
							staffStore.getStaffs().put(staff.getStaffId(), staffTitle);
						}
						else {
							staffTitle = (StaffReportTitle)staffStore.getStaffs().get(staff.getStaffId());
						}
						
						staffTitle.increaseMovieProcessed();
					}
				}
				
				mStaffReportStores = new ArrayList(stores.values());
			}
			
			return null;
	}
	
	public static class StaffReportStore implements Serializable {
		private Store mStore;
		private Map mStaffs = new HashMap();
		private int mMovieProcessed = 0;
		
		/**
		 * @param store
		 */
		public StaffReportStore(Store store) {
			mStore = store;
		}
		/**
		 * @return the store
		 */
		public Store getStore() {
			return mStore;
		}
		/**
		 * @param store the store to set
		 */
		public void setStore(Store store) {
			mStore = store;
		}
		/**
		 * @return the staffs
		 */
		public Map getStaffs() {
			return mStaffs;
		}
		/**
		 * @param staffs the staffs to set
		 */
		public void setStaffs(Map staffs) {
			mStaffs = staffs;
		}
		/**
		 * @return the movieProcessed
		 */
		public int getMovieProcessed() {
			return mMovieProcessed;
		}
		public void increaseMovieProcessed() {
			mMovieProcessed++;
		}
		
	}
	
	public static class StaffReportTitle implements Serializable {
		private Staff mStaff;
		private int mMovieProcessed = 0;
		
		/**
		 * @param staff
		 */
		public StaffReportTitle(Staff staff) {
			mStaff = staff;
		}

		/**
		 * @return the staff
		 */
		public Staff getStaff() {
			return mStaff;
		}

		/**
		 * @return the movieProcessed
		 */
		public int getMovieProcessed() {
			return mMovieProcessed;
		}
		public void increaseMovieProcessed() {
			mMovieProcessed++;
		}
	}
	
	public static class RentalReportStore implements Serializable {
		private Store mStore;
		private Map mTitles = new HashMap();
		private BigDecimal mTotalNormalCharge = BigDecimal.ZERO;
		private BigDecimal mTotalPenaltyCharge = BigDecimal.ZERO;
		
		/**
		 * @param store
		 */
		public RentalReportStore(Store store) {
			mStore = store;
		}
		/**
		 * @return the store
		 */
		public Store getStore() {
			return mStore;
		}
		/**
		 * @param store the store to set
		 */
		public void setStore(Store store) {
			mStore = store;
		}
		/**
		 * @return the titles
		 */
		public Map getTitles() {
			return mTitles;
		}
		/**
		 * @param titles the titles to set
		 */
		public void setTitles(Map titles) {
			mTitles = titles;
		}
		/**
		 * @return the totalCharge
		 */
		public BigDecimal getTotalCharge() {
			return mTotalNormalCharge.add(mTotalPenaltyCharge);
		}
		/**
		 * @return the totalNormalCharge
		 */
		public BigDecimal getTotalNormalCharge() {
			return mTotalNormalCharge;
		}
		/**
		 * @return the totalPenaltyCharge
		 */
		public BigDecimal getTotalPenaltyCharge() {
			return mTotalPenaltyCharge;
		}
		public void increaseTotalNormalCharge(BigDecimal value){
			if (value != null) {
				mTotalNormalCharge = mTotalNormalCharge.add(value);
			}
		}
		public void increaseTotalPenaltyCharge(BigDecimal value){
			if (value != null) {
				mTotalPenaltyCharge = mTotalPenaltyCharge.add(value);
			}
		}
	}
	
	public static class RentalReportTitle implements Serializable {
		private Title mTitle;
		private BigDecimal mTotalNormalCharge = BigDecimal.ZERO;
		private BigDecimal mTotalPenaltyCharge = BigDecimal.ZERO;
		
		/**
		 * @param title
		 */
		public RentalReportTitle(Title title) {
			mTitle = title;
		}
		/**
		 * @return the title
		 */
		public Title getTitle() {
			return mTitle;
		}
		/**
		 * @param title the title to set
		 */
		public void setTitle(Title title) {
			mTitle = title;
		}
		
		/**
		 * @return the totalCharge
		 */
		public BigDecimal getTotalCharge() {
			return mTotalNormalCharge.add(mTotalPenaltyCharge);
		}
		/**
		 * @return the totalNormalCharge
		 */
		public BigDecimal getTotalNormalCharge() {
			return mTotalNormalCharge;
		}
		/**
		 * @return the totalPenaltyCharge
		 */
		public BigDecimal getTotalPenaltyCharge() {
			return mTotalPenaltyCharge;
		}
		public void increaseTotalNormalCharge(BigDecimal value){
			if (value != null) {	
				mTotalNormalCharge = mTotalNormalCharge.add(value);
			}
		}
		public void increaseTotalPenaltyCharge(BigDecimal value){
			if (value != null) {
				mTotalPenaltyCharge = mTotalPenaltyCharge.add(value);
			}
		}
	}
	
	public static class StockReportStore implements Serializable {
		private Store mStore;
		private Map mTitles = new HashMap();
		private int mTotalCopies;
		private int mUnAvailableCopies;
		
		/**
		 * @param store
		 */
		public StockReportStore(Store store) {
			mStore = store;
		}
		/**
		 * @return the store
		 */
		public Store getStore() {
			return mStore;
		}
		/**
		 * @param store the store to set
		 */
		public void setStore(Store store) {
			mStore = store;
		}
		/**
		 * @return the titles
		 */
		public Map getTitles() {
			return mTitles;
		}
		/**
		 * @param titles the titles to set
		 */
		public void setTitles(Map titles) {
			mTitles = titles;
		}
		
		/**
		 * @return the totalCopies
		 */
		public int getTotalCopies() {
			return mTotalCopies;
		}
		/**
		 * @return the unAvailableCopies
		 */
		public int getUnAvailableCopies() {
			return mUnAvailableCopies;
		}
		/**
		 * @return the availableCopies
		 */
		public int getAvailableCopies() {
			return mTotalCopies - mUnAvailableCopies;
		}
		
		public void increaseTotalCopies() {
			this.mTotalCopies++;
		}
		public void increaseUnAvailableCopies() {
			this.mUnAvailableCopies++;
		}
	}
	
	public static class StockReportTitle implements Serializable {
		private Title mTitle;
		private int mTotalCopies;
		private int mUnAvailableCopies;
		
		/**
		 * @param title
		 */
		public StockReportTitle(Title title) {
			mTitle = title;
		}
		/**
		 * @return the title
		 */
		public Title getTitle() {
			return mTitle;
		}
		/**
		 * @param title the title to set
		 */
		public void setTitle(Title title) {
			mTitle = title;
		}
		
		/**
		 * @return the totalCopies
		 */
		public int getTotalCopies() {
			return mTotalCopies;
		}
		/**
		 * @return the unAvailableCopies
		 */
		public int getUnAvailableCopies() {
			return mUnAvailableCopies;
		}
		/**
		 * @return the availableCopies
		 */
		public int getAvailableCopies() {
			return mTotalCopies - mUnAvailableCopies;
		}
		
		public void increaseTotalCopies() {
			this.mTotalCopies++;
		}
		public void increaseUnAvailableCopies() {
			this.mUnAvailableCopies++;
		}
	}

}
